﻿using System;
using System.Text;
using System.Net;
using System.IO;
using WPP_Service.Data;
using Newtonsoft.Json;
using System.Windows;

namespace WPP_Console
{
    public static class ServiceClient
    {
        /// <summary>
        /// The base address of the IIS server.
        /// </summary>
        //private static string gsuServiceAddress = "http://23.23.80.142/InfoService/";
        private static string gsuServiceAddress = "http://141.165.12.253/WppService/";
        //private static string gsuServiceAddress = "http://localhost:60370/";

        #region Method Wrappers

        /// <summary>
        /// Wrapper for calling the GetOrders service method.
        /// </summary>
        /// <param name="oq">The OrderQuery will be used to filter results from the database.</param>
        /// <returns>
        /// The array of Orders returned matches the search criteria provided to the methdods. 
        /// Index 0 contains A response from the service detailing the sucecess of the call.
        /// </returns>
        public static Order[] GetOrders(OrderQuery oq)
        {
            string json = JsonConvert.SerializeObject(oq);
            string result = CallPostService("order", json);
            Order[] o;
            try
            {
                return (Order[])JsonConvert.DeserializeObject(result, typeof(Order[]));
            }
            catch (ArgumentNullException e)
            {
                o = new Order[1];
                o[0] = new Order();
                o[0].GetResponse = new GetResponse();
                o[0].GetResponse.ErrorMessage = "Data returned was null.";
            }
            return o;
        }

        /// <summary>
        /// Wrapper for calling the UpdatePackage service method.
        /// </summary>
        /// <param name="p">Applies any changes made in p to the object state in the database.</param>
        /// <returns>A response from the service detailing the sucecess of the call.</returns>
        public static InvokeResponse UpdatePackage(Package p)
        {
            string result = CallPutService("package", JsonConvert.SerializeObject(p));
            return (InvokeResponse)JsonConvert.DeserializeObject(result, typeof(InvokeResponse));
        }

        /// <summary>
        /// Wrapper for calling the UpdateOrder service method.
        /// </summary>
        /// <param name="p">Applies any changes made in o to the object state in the database.</param>
        /// <returns>A response from the service detailing the sucecess of the call.</returns>
        public static InvokeResponse UpdateOrder(Order o)
        {
            string result = CallPutService("order", JsonConvert.SerializeObject(o));
            return (InvokeResponse)JsonConvert.DeserializeObject(result, typeof(InvokeResponse));        
        }

        /// <summary>
        /// Wrapper for calling the BatchClear method.
        /// </summary>
        /// <param name="dg">DateGroup having DateType of BATCH_CLEAR and a date range to mark as cleared.</param>
        /// <returns>A response from the service detailing the sucecess of the call.</returns>
        public static InvokeResponse BatchClear(DateGroup dg)
        {
            string result = CallPostService("clear", JsonConvert.SerializeObject(dg));
            return (InvokeResponse)JsonConvert.DeserializeObject(result, typeof(InvokeResponse));
        }

        #endregion

        #region Client Communication

        /// <summary>
        /// Retrieves data from the service via HTTP GET. GET must not affect the state of the database.
        /// </summary>
        /// <param name="url">The url of the service endpoint</param>
        /// <returns>The response from the service as a JSON string</returns>
        private static string CallGetService(string url)
        {
            url = gsuServiceAddress + url;
            // declare httpwebrequest with url defined above
            HttpWebRequest webrequest = (HttpWebRequest)WebRequest.Create(url);
            webrequest.Method = "GET";
            webrequest.Credentials = new NetworkCredential("Administrator", "Hermes_01");
            webrequest.ContentType = "application/x-www-form-urlencoded";

            // set up certificate trust
            /*ServicePointManager.ServerCertificateValidationCallback =
            new RemoteCertificateValidationCallback(
            delegate(object sender2, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            });*/
            // declare & read response from service
            HttpWebResponse webresponse;
            Encoding enc;
            StreamReader responseStream;
            string strResult = string.Empty;
            try
            {
                webresponse = (HttpWebResponse)webrequest.GetResponse();
                enc = System.Text.Encoding.GetEncoding("utf-8");
                responseStream = new StreamReader(webresponse.GetResponseStream(), enc);
                strResult = responseStream.ReadToEnd();
                responseStream.Close();
                webresponse.Close();
            }
            catch (WebException we)
            {
                strResult = "A Web Exception has occurred\n\n" + we.Message;
            }

            return strResult;
        }

        /// <summary>
        /// Sends data to the service via the HTTP PUT. PUT must be idempotent.
        /// </summary>
        /// <param name="uriTemplate">The uri template for the desired method.</param>
        /// <param name="jsonData">The JSON object to send.</param>
        /// <returns></returns>
        private static string CallPutService(string uriTemplate, string jsonData)
        {
            string url = gsuServiceAddress + uriTemplate;
            byte[] buffer = Encoding.UTF8.GetBytes(jsonData);
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.Method = "PUT";
            request.Credentials = new NetworkCredential("Administrator", "Hermes_01");
            request.ContentType = "application/x-www-form-urlencoded";

            // set up certificate trust
            /*ServicePointManager.ServerCertificateValidationCallback =
            new RemoteCertificateValidationCallback(
            delegate(object sender2, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            });*/
            using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
            {
                sw.Write(jsonData);
                Console.WriteLine(jsonData);
                sw.Close();
            }
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                string res = sr.ReadToEnd();
                return res;
            }
        }

        /// <summary>
        /// Sends data to the service via the HTTP POST. POST is not guaranteed idempotent.
        /// </summary>
        /// <param name="uriTemplate">The uri template for the desired method.</param>
        /// <param name="jsonData">The JSON object to send.</param>
        /// <returns></returns>
        private static string CallPostService(string uriTemplate, string jsonData)
        {
            string url = gsuServiceAddress + uriTemplate;
            byte[] buffer = Encoding.UTF8.GetBytes(jsonData);
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.Method = "POST";
            request.Credentials = new NetworkCredential("Administrator", "Hermes_01");
            request.ContentType = "application/x-www-form-urlencoded";
            //request.Timeout = 10000;

            // set up certificate trust
            /*ServicePointManager.ServerCertificateValidationCallback =
            new RemoteCertificateValidationCallback(
            delegate(object sender2, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
            {
                return true;
            });*/
            using (StreamWriter sw = new StreamWriter(request.GetRequestStream()))
            {
                sw.Write(jsonData);
                Console.WriteLine(jsonData);
                sw.Close();
            }
            HttpWebResponse response = null;
            try
            {
                response = (HttpWebResponse)request.GetResponse();
            }
            catch (WebException e)
            {
                if (e.Status == WebExceptionStatus.Timeout) MessageBox.Show("The request timed out. If this problem persists, please contact your system administrator");
                else MessageBox.Show("An error occured when sending the request to the server.\n\nError Code: " + e.Status);
                return null;
            }
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                string res = sr.ReadToEnd();
                return res;
            }
        }

        #endregion
    }
}
